package net.sudot.chess.business.service;

import net.sudot.chess.exception.BusinessException;
import net.sudot.chess.business.dao.SystemConfigDao;
import net.sudot.chess.business.dto.EnumDTO;
import net.sudot.chess.business.dto.ReflectFieldDTO;
import net.sudot.chess.business.model.SystemConfig;
import net.sudot.chess.business.model.enums.SystemConfigType;
import net.sudot.chess.config.SystemProperties;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;

/**
 * 游戏分类
 *
 * @author tangjialin on 2018-02-27.
 */
@Service
public class SystemConfigService extends BaseService<SystemConfig> {

    @Resource
    private SystemConfigDao systemConfigDao;
    @Resource
    private SystemProperties systemProperties;

    /**
     * 获取所有系统配置
     *
     * @return 返回所有系统配置项
     */
    public List<SystemConfig> findAll() {
        return systemConfigDao.findAll();
    }

    /**
     * 获取指定属性的系统配置
     *
     * @param attributeKey 属性键
     * @return 返回其配置信息
     */
    public SystemConfig find(String attributeKey) {
        return systemConfigDao.find(SystemConfig.ATTRIBUTE_KEY, attributeKey);
    }

    /**
     * 获得属性的字段对象
     *
     * @param attributeKey 属性键
     * @return 返回其字段对象
     * @throws BusinessException
     */
    public ReflectFieldDTO getReflectField(String attributeKey) {
        try {
            String[] split = attributeKey.split("\\.");
            Object o = systemProperties;
            Class<?> propertiesClass = systemProperties.getClass();
            int lastIndex = split.length - 1;
            Field field = null;
            for (int i = 0; i <= lastIndex; i++) {
                String key = split[i];
                field = propertiesClass.getDeclaredField(key);
                field.setAccessible(true);
                if (i < lastIndex) {
                    o = field.get(o);
                    propertiesClass = o.getClass();
                }
            }
            return new ReflectFieldDTO(o, field);
        } catch (Exception e) {
            throw new BusinessException("属性获取错误:" + attributeKey, e);
        }
    }

    /**
     * 获取枚举类型的枚举项
     *
     * @param attributeKey 属性键
     * @return 枚举项
     * @throws BusinessException
     */
    @SuppressWarnings("unchecked")
    public List<EnumDTO> getOptions(String attributeKey) {
        Field field = getReflectField(attributeKey).getField();
        if (field == null) { return null; }
        Class<Enum> type = (Class<Enum>) field.getType();
        if (!type.isEnum()) { return null; }
        List<EnumDTO> enumDTOList = new ArrayList<>();
        try {
            EnumSet enumSet = EnumSet.allOf(type);
            for (Iterator iterator = enumSet.iterator(); iterator.hasNext(); ) {
                Enum anEnum = (Enum) iterator.next();
                Method memo = anEnum.getDeclaringClass().getDeclaredMethod("memo");
                enumDTOList.add(new EnumDTO(anEnum.ordinal(), anEnum.name(), memo.invoke(anEnum).toString()));
            }
            return enumDTOList;
        } catch (Exception e) {
            throw new BusinessException("枚举项获取失败:" + attributeKey, e);
        }
    }

    /**
     * 获取字段的配置类型
     *
     * @param field 字段
     * @return 返回其类型
     */
    public SystemConfigType getSystemConfigType(Field field) {
        Class<?> fieldType = field.getType();
        if (fieldType == String.class) {
            return SystemConfigType.STRING;
        } else if (fieldType.isEnum()) {
            return SystemConfigType.ENUM;
        } else if (TemporalAccessor.class.isAssignableFrom(fieldType)) {
            return SystemConfigType.DATE;
        }
        return SystemConfigType.STRING;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SystemConfig saveOrUpdate(SystemConfig config) {
        try {
            ReflectFieldDTO reflectField = getReflectField(config.getAttributeKey());
            reflectField.setValue(config.getAttributeType().deserialize(config.getAttributeValue(), reflectField.getField().getType()));
        } catch (Exception e) {
            throw new BusinessException("属性更新异常:" + config.getAttributeKey());
        }
        return super.saveOrUpdate(config);
    }

}
